﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SnelsteRoute
{
    class RouteFinder
    {
        internal static List<Route> FindRoutes(SearchRequest req)
        {
            return FindRoutes(req.From, req.To, req.MaxHops);
        }

        internal static List<Route> FindRoutes(Aspect start, Aspect finish,Int32 nrOfHops)
        {
            var finishedRoutes = new List<Route>();
            var routesInProgress = new List<Route>();
            var models = Models.GetInstance();
            var finishedRoutesCutoffMoment = ConfigHelper.GetInt32(ConfigHelper.ConfigFinishedRouteCutOff, 1500);
            
            models.FinishedRoutes = 0;
            models.LocatedRoutes = 0;

            models.Activity = "Seeding Pathfinder";

            //  add primary routes (child)
            foreach(var child in start.ChildAspects)
            {
                var newRoute = new Route();
                newRoute.AddAspect(start);
                newRoute.AddAspect(child);
                routesInProgress.Add(newRoute);
            }
            //  add primary routes (parent)
            foreach (var parent in start.DerivedAspects)
            {
                var newRoute = new Route();
                newRoute.AddAspect(start);
                newRoute.AddAspect(parent);
                routesInProgress.Add(newRoute);
            }

            // while there is work, process
            while (routesInProgress.Count > 0)
            {
                // we could check finished routes first, but a two-hop route is useless in Thaumcraft.

                var index = 0;
                var iterationRoutes = new List<Route>();

                models.Activity = "Pathfinding to next aspect";

                foreach(var currentRoute in routesInProgress)
                {
                    // an Aspect always has either 1 or 2 child aspects
                    if (currentRoute.LastAspect != null)
                    {
                        // add index 2
                        if (currentRoute.LastAspect.ChildAspects.Count > 0)
                        {
                            var clone = currentRoute.Clone();
                            clone.AddAspect(currentRoute.LastAspect.ChildAspects[0]);
                            iterationRoutes.Add(clone);

                            if (currentRoute.LastAspect.ChildAspects.Count > 1)
                            {
                                var clone2 = currentRoute.Clone();
                                clone2.AddAspect(currentRoute.LastAspect.ChildAspects[1]);
                                iterationRoutes.Add(clone2);
                            }
                        }
                    }

                    // then make routes for the parent aspects
                    foreach(var parentAspect in currentRoute.LastAspect.DerivedAspects)
                    {
                        var cloneDerived = currentRoute.Clone();
                        cloneDerived.AddAspect(parentAspect);
                        iterationRoutes.Add(cloneDerived);
                    }

                    // dont update binding too often
                    if (index % 50 == 0)
                        models.ScanIndex = index;

                    index++;
                }

                models.LocatedRoutes = iterationRoutes.Count;

                models.Activity = "Checking located routes";

                //check complete  and overlong routes
                var checkIndex = 0;
                var loops = 0;
                while (checkIndex < iterationRoutes.Count)
                {
                    var route = iterationRoutes[checkIndex];

                    if (route.IsComplete(start, finish, nrOfHops))
                    {
                        finishedRoutes.Add(route);
                        iterationRoutes.Remove(route);
                        models.FinishedRoutes ++;

                        //  this occurs when you make a route that is 7-8 or longer, it just takes too long
                        if (models.FinishedRoutes > finishedRoutesCutoffMoment)
                        {
                            return finishedRoutes;
                        }
                    }
                    else if (route.IsInvalid(nrOfHops))
                    {
                        iterationRoutes.Remove(route);
                    }
                    else
                    {
                        checkIndex++;
                    }

                    // dont update binding too often
                    if (loops % 50 == 0)
                        models.ScanIndex = loops;

                    loops ++;
                }

                // assign iteration to inProgress
                routesInProgress.Clear();
                routesInProgress = iterationRoutes;

            } //end of while
            
            return finishedRoutes;
        }
    }
}
